package com.github.dengmin.mysql.shiro.jwt;

import com.github.dengmin.mysql.shiro.cache.LoginRedisService;
import com.github.dengmin.mysql.shiro.service.ShiroLoginService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author dengmin
 * @Created 2020/8/14 上午9:53
 */
@Slf4j
public class JwtFilter extends AuthenticatingFilter {
    private static final long serialVersionUID = 1L;

    private ShiroLoginService shiroLoginService;
    private JwtProperties jwtProperties;
    private LoginRedisService loginRedisService;

    public JwtFilter(ShiroLoginService shiroLoginService, LoginRedisService loginRedisService, JwtProperties jwtProperties){
        this.shiroLoginService = shiroLoginService;
        this.loginRedisService = loginRedisService;
        this.jwtProperties = jwtProperties;
    }

    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        String token = JwtUtil.getToken();
        if(StringUtils.isBlank(token)){
            throw new AuthenticationException("token不能为空");
        }
        if(JwtUtil.isExpired(token)){
            throw new AuthenticationException("JWT Token已过期");
        }
        if(jwtProperties.isRedisCheck()){
            boolean redisExist = loginRedisService.exists(token);
            if(!redisExist){
                throw new AuthenticationException("redis中不存在Token");
            }
        }
        String username = JwtUtil.getUsername(token);
        String salt;
        if(jwtProperties.isSaltCheck()){
            salt = loginRedisService.getSalt(username);
        }else{
            salt = jwtProperties.getSecret();
        }
        return JwtToken.build(token, username, salt, jwtProperties.getExpireSecond());
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        HttpServletRequest request = WebUtils.toHttp(servletRequest);
        HttpServletResponse response = WebUtils.toHttp(servletResponse);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        String url = request.getRequestURI();
        return false;
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue){
        if(this.isLoginRequest(request, response)){
            return true;
        }
        boolean allowed = false;
        try{
            allowed = executeLogin(request, response);
        }catch (Exception e){
            log.error("访问错误", e);
        }
        return allowed || super.isPermissive(mappedValue);
    }

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        String url = WebUtils.toHttp(request).getRequestURI();
        log.debug("鉴权成功, token: {}, url: {}", token, url);
        JwtToken jwtToken = (JwtToken) token;
        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
        shiroLoginService.refreshToken(jwtToken, httpServletResponse);
        return true;
    }

    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        log.error("登录失败, toekn: " +token +" , error: "+e.getMessage(), e);
        return false;
    }
}
